/*
	Copyright (c) 2008, Grant Jones <grant@podtronics.com>.
	All rights reserved.

	Redistribution and use in source and binary forms, with or
	without modification, are permitted provided that the following
	conditions are met:

		Redistributions of source code must retain the above copyright
		notice, this list of conditions and the following disclaimer.
		
		Redistributions in binary form must reproduce the above copyright
		notice, this list of conditions and the following disclaimer in
		the documentation and/or other materials provided with the
		distribution.
		
		Neither the name of the gxjones.com nor the names of its
		contributors may be used to endorse or promote products derived
		from this software without specific prior written permission.
	
	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
	"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
	LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
	FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
	COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
	SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
	OF THE POSSIBILITY OF SUCH DAMAGE.
	
	http://www.opensource.org/licenses/bsd-license.php
*/

/*
 *  tagm.h
 *  edb
 *
 *  Created by Grant Jones on 4/30/07.
 *
 *
 *  Tag Manager Routines:
 *  hierarchial linked-list storage
 *
 *  About: Originally created for managing tags for mail in an
 *  email application.
 *
 */

#ifndef TAGM_H
#define TAGM_H

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>

#include <sys/uio.h>


#include <assert.h>

/*

Tag File Layout:

[TagStruct]: root tag -- could store actual key/data (but it would be immutable after creation)
[TagStruct]: deleted tags root
[TagStruct][key][data]: first child tag of the root item
[TagStruct][key][data]: second tag or first child-tag item of
etc.


0:[TagStruct hdr: root (next=0,prev=0,parent=0,first=100,last=400)]
	100:[TagStruct hdr: next = 400, prev = 0, parent = 0, first = 200, last = 300][key][data]
		200:[TagStruct hdr: next = 300, prev = 0, parent = 100, first = 0, last = 0][key][data]
		300:[TagStruct hdr: next = 0, prev = 200, parent = 100, first = 0, last = 0][key][data]
	400:[TagStruct hdr: next = 0, prev = 400, parent = 0, first = 500, last = 500][key][data]
		500:[TagStruct hdr: next = 0, prev = 0, parent = 400][key][data]



TODOS:
- implement deleted/unlinked item free space reclaiming/defragmenter
- basic tag buffering
- improved reserve space (allocator)

Notes:
- it is possible to cause orphaned items by unlinking an item (w/o reassigning it via tagm_changeTagParent)
 

Transaction Notes:
- starting a transaction will begin caching of all operations performed on
  on the file.
- abort/rollbacks are simply do not commit the change to the file


*/

#define TAGM_ERROR(X) printf X
//#define TAGM_TRACE(X) printf X
#define TAGM_TRACE void

/*!
	@defined TAG_OVERFLOW
	@discussion Tags marked with overflow are considered data appended to
		the parent tag.
*/
#define TAG_OVERFLOW		0x01
/*!
	@defined TAG_DELETED
	@discussion Tags marked with delete are considered deleted and invisible to
		enumeration. The tags are however still linked into the tags list, which
		should be considered for performance reasons.
*/
#define TAG_DELETED			0x02

#pragma pack(1)

typedef struct
{
	unsigned char bFlags;

	off_t parent;
	
	off_t prev;
	off_t next;

	off_t first;
	off_t last;
	
	size_t dlen;
	size_t klen;
} TagHdrStruct;

typedef struct
{
	TagHdrStruct hdr;
	unsigned char *key;
	unsigned char *data;
} TagStruct;

#pragma pack()

typedef struct
{
	off_t cur_loc;		// during tag enumeration this is set to the current tag location
	size_t data_alloc_sz;
	size_t key_alloc_sz;
	TagStruct curTag;
} TagManagerEnumStruct;

//#define TAGM_DEBUG_NAME

typedef struct
{
	int fd;
	off_t tag_file_sz;
	int enable_fsync;	/* true : enables fsync call on transaction */
	void *transactions;

#ifdef TAGM_DEBUG_NAME
	char name[256];
#endif
} TagManagerStruct;



TagManagerStruct *tagm_open( const char *tags_filename );
void tagm_close( TagManagerStruct *tags );
int tagm_duplicateTagFile( TagManagerStruct *source_tags, TagManagerStruct *dest_tags, off_t src_start_loc, off_t dst_start_loc );

int tagm_zerofile( TagManagerStruct *tags );


/* Internal functions */

off_t tagm_reserveSpace( TagManagerStruct *tags, size_t size );


/* tagm interface functions */
int tagm_beginEnumTags( TagManagerStruct *tags, TagManagerEnumStruct *tmes, off_t root_loc );
int tagm_endEnumTags( TagManagerStruct *tags, TagManagerEnumStruct *tmes );
TagStruct *tagm_nextTag( TagManagerStruct *tags, TagManagerEnumStruct *tmes, off_t *tag_loc );
int tagm_nextTagHeader( TagManagerStruct *tags, TagManagerEnumStruct *tmes, off_t *tag_loc, TagHdrStruct *tag_hdr );

int tagm_insertTag( TagManagerStruct *tags, off_t root_loc, TagStruct *new_tag, off_t *new_tag_loc );

TagStruct *tagm_readTag( TagManagerStruct *tags, off_t tag_loc, int bReadFullEntry );

void tagm_dumpTag( TagManagerStruct *tags, FILE *out_fp, off_t start_loc, int indent );

int tagm_changeTagParent( TagManagerStruct *tags, off_t tag_loc, off_t new_parent_loc );
int tagm_unlinkTag( TagManagerStruct *tags, off_t tag_loc );
int tagm_deleteTag( TagManagerStruct *tags, off_t tag_loc );

void tagm_freeTag( TagStruct *tag );

#endif


